import java.awt.Color;

public class CBoard{
  public Color[] _board;
  public int _passes;
  public Color _curPlayer;
  public Color _otherPlayer;
  public boolean[] _curValidMoves;
  public boolean[] _otherValidMoves;
  public boolean isGameOver;

  public CBoard(){
    _board = new Color[64];
    _passes = 0;
    _curPlayer = Color.WHITE;
    _otherPlayer = Color.BLACK;
    _board[27] = _curPlayer;
    _board[28] = _otherPlayer;
    _board[35] = _otherPlayer;
    _board[36] = _curPlayer;
    _curValidMoves = new boolean[64];
    _otherValidMoves = new boolean[64];
    setValidMoves();
    isGameOver = false;
  }

  public CBoard(IBoard board, Color us, Color them){
    _board = new Color[64];
    _passes = 0;
    _curPlayer = us;
    _otherPlayer = them;
    for (int r = 0; r < 8; r++)
      for (int c = 0; c < 8; c++)
        _board[(r<<3) | c] = board.playerAt(r, c);
    _curValidMoves   = new boolean[64];
    _otherValidMoves = new boolean[64];
    setValidMoves();
    isGameOver = board.isGameOver();
  }

  public CBoard(CBoard parent, Integer move){
    _board = new Color[64];
    isGameOver = true;
    for (int i = 0; i < 64; i++){
      _board[i] = parent._board[i];
      if (_board[i] == null) isGameOver = false;
    }
    _curPlayer = parent._otherPlayer;
    _otherPlayer = parent._curPlayer;
    if (move != 64){
      _board[move] = parent._curPlayer;
      flipLines(move);
      _passes = 0;
    }
    else{
      _passes = parent._passes + 1;
    }
    if (_passes == 2)
      isGameOver = true;
    _curValidMoves   = new boolean[64];
    _otherValidMoves = new boolean[64];
    setValidMoves();
  }

  public void setValidMoves(){
    // we might be able to skip _otherValidMoves as long as we're not a leaf node
    // (only evaluation function uses it)
    for (int i = 0; i < 64; i++){
      if      (_board[i] != null) _curValidMoves[i] = false;
      else if (isValidLine(i, 8)) _curValidMoves[i] = true;     // down
      else if (isValidLine(i,-8)) _curValidMoves[i] = true;     // up
      else if (isValidLine(i, 1)) _curValidMoves[i] = true;     // right
      else if (isValidLine(i,-1)) _curValidMoves[i] = true;     // left
      else if (isValidLine(i, 9)) _curValidMoves[i] = true;     // down-right
      else if (isValidLine(i, 7)) _curValidMoves[i] = true;     // down-left
      else if (isValidLine(i,-7)) _curValidMoves[i] = true;     // up-right
      else if (isValidLine(i,-9)) _curValidMoves[i] = true;     // up-left
      else _curValidMoves[i] = false;
    }

    for (int i = 0; i < 64; i++){
      if      (_board[i] != null)  _otherValidMoves[i] = false;
      else if (isEValidLine(i, 8)) _otherValidMoves[i] = true;  // down
      else if (isEValidLine(i,-8)) _otherValidMoves[i] = true;  // up
      else if (isEValidLine(i, 1)) _otherValidMoves[i] = true;  // right
      else if (isEValidLine(i,-1)) _otherValidMoves[i] = true;  // left
      else if (isEValidLine(i, 9)) _otherValidMoves[i] = true;  // down-right
      else if (isEValidLine(i, 7)) _otherValidMoves[i] = true;  // down-left
      else if (isEValidLine(i,-7)) _otherValidMoves[i] = true;  // up-right
      else if (isEValidLine(i,-9)) _otherValidMoves[i] = true;  // up-left
      else _otherValidMoves[i] = false;
    }
  }

  public boolean isValidLine(int theoPos, int move){    // for curPlayer
    int side = move % 8;
    side = (side ==  7)? -1 : side;
    side = (side == -7)?  1 : side;
    int squares = -1;
    do {
      theoPos += move;
      squares ++;
      if (theoPos < 0 || theoPos >= 64 || ((theoPos & 7) - side) < 0 ||
          ((theoPos & 7) - side) >= 8) return false;
    } while (_board[theoPos] == _otherPlayer);
    // if this is false, theoPos is null
    if (_board[theoPos] == _curPlayer && squares >= 1) return true;
    return false;
  }

  public boolean isEValidLine(int theoPos, int move){   // for otherPlayer
    int side = move % 8;
    side = (side ==  7)? -1 : side;
    side = (side == -7)?  1 : side;
    int squares = -1;
    do {
      theoPos += move;
      squares ++;
      if (theoPos < 0 || theoPos >= 64 || ((theoPos & 7) - side) < 0 ||
          ((theoPos & 7) - side) >= 8) return false;
    } while (_board[theoPos] == _curPlayer);
    // if this is false, theoPos is null
    if (_board[theoPos] == _otherPlayer && squares >= 1) return true;
    return false;
  }

  public void flipLines(int pos){ // for otherPlayer
    // remove boundary checks next revision
    int tmp;
    if (isEValidLine(pos, 8)){ // down
      tmp = pos;
      do {
        _board[tmp] = _otherPlayer;
        tmp += 8;
      } while (_board[tmp] == _curPlayer && tmp < 64);
    }
    if (isEValidLine(pos,-8)){ // up
      tmp = pos;
      do {
        _board[tmp] = _otherPlayer;
        tmp -= 8;
      } while (_board[tmp] == _curPlayer && tmp >= 0);
    }
    if (isEValidLine(pos, 1)){ // right
      tmp = pos;
      do {
        _board[tmp] = _otherPlayer;
        tmp += 1;
      } while (_board[tmp] == _curPlayer && (tmp & 7) != 0);
    }
    if (isEValidLine(pos,-1)){ // left
      tmp = pos;
      do {
        _board[tmp] = _otherPlayer;
        tmp -= 1;
      } while (_board[tmp] == _curPlayer && (tmp & 7) != 7);
    }
    if (isEValidLine(pos, 9)){ // down-right
      tmp = pos;
      do {
        _board[tmp] = _otherPlayer;
        tmp += 9;
      } while (_board[tmp] == _curPlayer && tmp < 64 && (tmp & 7) != 0);
    }
    if (isEValidLine(pos, 7)){ // down-left
      tmp = pos;
      do {
        _board[tmp] = _otherPlayer;
        tmp += 7;
      } while (_board[tmp] == _curPlayer && tmp < 64 && (tmp & 7) != 7);
    }
    if (isEValidLine(pos,-7)){ // up-right
      tmp = pos;
      do {
        _board[tmp] = _otherPlayer;
        tmp -= 7;
      } while (_board[tmp] == _curPlayer && tmp >= 0 && (tmp & 7) != 0);
    }
    if (isEValidLine(pos,-9)){ // up-left
      tmp = pos;
      do {
        _board[tmp] = _otherPlayer;
        tmp -= 9;
      } while (_board[tmp] == _curPlayer && tmp >= 0 && (tmp & 7) != 7);
    }
  }

}
